#include <stdlib.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include "pool.h"

#define STEP 2  //增减线程数

static void *admin_job(void *arg);
static void *worker_job(void *arg);
int pool_init(pool_t **mypool, int capacity){
	pool_t *me = NULL;
	int err, i;

	me = malloc(sizeof(pool_t));
	if(NULL == me){
		perror("malloc");
		return -errno;
	}

	me->workers = calloc(capacity, sizeof(pthread_t));
	if(NULL == me->workers){
		free(me);
		perror("calloc");
		return -errno;
	}
	queue_init(&me->task_queue, MAXJOB, sizeof(task_t));
	me->max_threads = capacity;
	me->min_free_threads = MIN_FREETHR_NR;
	me->max_free_threads = MAX_FREETHR_NR;
	me->busy_threads = 0;
	me->live_threads = me->min_free_threads;
	pthread_mutex_init(&me->mut_pool, NULL);
	pthread_mutex_init(&me->mut_busy, NULL);
	pthread_cond_init(&me->queue_not_empty, NULL);
	pthread_cond_init(&me->queue_not_full, NULL);
	me->exit_threads = 0;
	me->shutdown = 0;

	//构建管理者线程
	err = pthread_create(&me->admin_ttid, NULL, admin_job, me);
	if(err){
		fprintf(stderr, "pthread admin create is failed\n");
		free(me->workers);
		free(me);
		return -err;
	}
	//创建线程池中最少free线程
	for(i = 0; i < me->min_free_threads; i++){
		err = pthread_create(me->workers + i, NULL, worker_job, me);
		if(err){
			fprintf(stderr, "pthread worker create is failed\n");
			free(me->workers);
			free(me);
			return -err;
		}
		//线程分离
		pthread_detach((me->workers)[i]);
	}


	*mypool = me;
	return 0;
}

//找到工作线程数组中空闲的位置
static int __get_free_pos(pthread_t *jobs, int n){
	int i;
	for(i = 0; i < n; i++){
		// 检测线程是否存在
		if(0 == pthread_kill(jobs[i], 0))
			return i; //返回空闲位置
	}
	return -1;
}

//管理者线程函数
static void *admin_job(void *arg){
	/*
	 周期性查看县城池中busy的线程个数和free的线程个数，适当增减线程
   例如1s一次
	while(1){
		//拿到线程池的互斥量
		//获取busy_cnt, free_cnt
		//free_cnt > MAX_FREETHR_NR 减少2
		//free_cnt == 0; 增加2
		sleep(1);
	}	
	问题：如何减少线程？
		方式1：取消
		方式2：自杀
			exit_threads 增加数值，发送queue_not_empty通知

	 */
	int i, pos;
	pool_t *mypool = arg;
	int free_cnt, busy_cnt;

	while(1){
		pthread_mutex_lock(&mypool->mut_pool);
		if(mypool->shutdown){
			pthread_mutex_unlock(&mypool->mut_pool);
			break;
		}
		pthread_mutex_lock(&mypool->mut_busy);
		busy_cnt = mypool->busy_threads; 
		pthread_mutex_unlock(&mypool->mut_busy);
		free_cnt = mypool->live_threads - busy_cnt;
		
		// 减少
		if(free_cnt >= mypool->max_free_threads + STEP){
			mypool->exit_threads = STEP;
			for (i = 0; i < STEP; i++)
				pthread_cond_signal(&mypool->queue_not_empty);
		}

		// 增加
		if(busy_cnt == mypool->live_threads && mypool->live_threads < mypool-> max_threads){
			for(i = 0; i < STEP; i++){
				pos = __get_free_pos(mypool->workers, mypool->max_threads);
				if (-1 == pos){
					//没位置了
					fprintf(stderr, "[%d]__get_free_pos() failed\n", __LINE__);
				}
				pthread_create(mypool->workers + pos, NULL, worker_job, mypool);
				pthread_detach((mypool->workers)[pos]);
				mypool->live_threads++;
			}
		}
		// 测试语句——> 打印县城池中线程的个数
		
			for(i = 0; i < mypool->busy_threads; i++){
				write(1, "O", 1);
			}
			for(i = 0;i < mypool->live_threads - mypool->busy_threads; i++){
				write(1, "X", 1);
			}
			write(1, "\n", 1);
		pthread_mutex_unlock(&mypool->mut_pool);
		sleep(1);
	}

	pthread_exit(0);
}

// 工作线程的函数
static void *worker_job(void *arg){
	/*
	   循环
	   	抢锁---》判断任务队列是否为空
			为空
				解锁等待queue_not_empty通知
				通知来了
					情况1：池关闭了
					情况2：exit_threads>0 中止
					情况3：任务对列真的来任务了，出队，busy个数增加，做任务，任务做完了，循环
	   */
	pool_t *mypool = arg;
	task_t mytask;

	while(1){
		pthread_mutex_lock(&mypool->mut_pool);

		if(queue_is_empty(mypool->task_queue)){
			pthread_cond_wait(&mypool->queue_not_empty, &mypool->mut_pool);
		}
		if(mypool ->shutdown){//池关闭先解锁，防止死锁
			pthread_mutex_unlock(&mypool->mut_pool);
			break;
		}
		if(mypool->exit_threads > 0){
			mypool->exit_threads--;
			pthread_mutex_unlock(&mypool->mut_pool);
			break;
		}
		// 任务来了
		queue_deq(mypool->task_queue, &mytask);
		pthread_cond_signal(&mypool->queue_not_full);
		pthread_mutex_unlock(&mypool->mut_pool);

		//做任务
		pthread_mutex_lock(&mypool->mut_busy);
		mypool->busy_threads++;
		pthread_mutex_unlock(&mypool->mut_busy);

		(mytask.job)(mytask.arg);
		pthread_mutex_lock(&mypool->mut_busy);
		mypool->busy_threads--;
		pthread_mutex_unlock(&mypool->mut_busy);
	}
	pthread_exit(0);
}

int pool_add_task(pool_t *mypool, const task_t *t){
	pthread_mutex_lock(&mypool->mut_pool);
	while(queue_is_full(mypool->task_queue)){
		pthread_cond_wait(&mypool->queue_not_full, &mypool->mut_pool);
	}
	queue_enq(mypool->task_queue, t);
	pthread_cond_signal(&mypool->queue_not_empty);
	pthread_mutex_unlock(&mypool->mut_pool);

	return 0;
}

void pool_destroy(pool_t *mypool){
	pthread_mutex_lock(&mypool->mut_pool);
	mypool->shutdown = 1;
	pthread_cond_broadcast(&mypool->queue_not_empty);
	pthread_mutex_unlock(&mypool->mut_pool);
	
	sleep(1); //线程分离不会合， 阻塞1s为了等线程得到shutdown通知
	free(mypool->workers);
	queue_destory(&mypool->task_queue);
	pthread_mutex_destroy(&mypool->mut_pool);
	pthread_mutex_destroy(&mypool->mut_busy);
	pthread_cond_destroy(&mypool->queue_not_empty);
	pthread_cond_destroy(&mypool->queue_not_full);
	free(mypool);

}